package msi.gama.display.java3d.renderingObject;

import javax.media.j3d.Appearance;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.PolygonAttributes;
import javax.vecmath.Color3f;

import msi.gama.metamodel.shape.IShape;

import com.sun.j3d.utils.geometry.Primitive;

/**
 * minhvv, p18, IFI, TPE 01/2014 - 07/2014
 */

public class VisualObject implements IChangedObject {

	private IShape geometry;
	private Color3f color;
	private Color3f borderColor;
	private boolean isFilled;
	private boolean isRounded;

	private Primitive primitiveShape;
	private Appearance appearance;
	private ColoringAttributes coloringAttribute;
	private PolygonAttributes polygonAttribute;

	private VisualObject buffer = null;

	public VisualObject(IShape geometry, Color3f color, Color3f borderColor,
			boolean isFilled, boolean isRounded) {
		this.geometry = geometry;
		this.color = color;
		this.borderColor = borderColor;
		this.isFilled = isFilled;
		this.isRounded = isRounded;

		createGeometry();
	}

	public Primitive getPrimitiveShape() {
		return this.primitiveShape;
	}

	/*
	 * FOR GEOMETRY VISUAL-DISPLAY
	 */

	private void createGeometry() {
		_createShpae();
		_createAppearance();
		_createColorAtrribute();
		_createPolygonAttribute();

		_applyChangingGeometry();
	}

	private void _applyChangingGeometry() {
		_applyPolygonModeToAppearance();
		_applyColorToAppearance();
		_applyAppearanceToShape();
	}

	private void _createShpae() {
		// FIXME minhvv can not find solution to get object info ( radius of
		// sphere, size of box, ... )
		float minhvvHardCodeRaidus = 0.01f;
		this.primitiveShape = GeometryFactory.createPrimitive(
				geometry.getGeometricalType(), minhvvHardCodeRaidus);
		this.primitiveShape.setCapability(Primitive.ENABLE_APPEARANCE_MODIFY);
	}

	private void _createAppearance() {
		this.appearance = new Appearance();
		this.appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
		this.appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
		this.appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_READ);
		this.appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE);
	}

	private void _createColorAtrribute() {
		this.coloringAttribute = new ColoringAttributes();
		this.coloringAttribute.setCapability(ColoringAttributes.ALLOW_COLOR_READ);
		this.coloringAttribute.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE);
		this.coloringAttribute.setColor(this.color);
	}

	private void _createPolygonAttribute() {
		this.polygonAttribute = new PolygonAttributes();
		polygonAttribute.setCullFace(PolygonAttributes.CULL_NONE);
	}

	private void _applyColorToAppearance() {
		this.appearance.setColoringAttributes(this.coloringAttribute);
	}

	private void _applyAppearanceToShape() {
		this.primitiveShape.setAppearance(this.appearance);
	}

	private void _applyPolygonModeToAppearance() {
		if (!isFilled) {
			this.appearance.setPolygonAttributes(polygonAttribute);
		}
	}

	/*
	 * FOR BUFFER DATA
	 */

	public void setNewData(IShape geometry, Color3f color, Color3f borderColor,
			boolean isFilled, boolean isRounded) {
		this.buffer = new VisualObject(geometry, color, borderColor, isFilled, isRounded);

		processChangeData();
		cleanBufferData();

	}

	@Override
	public void processChangeData() {
		_processChangeGeometry();
	}

	@Override
	public void cleanBufferData() {
		this.buffer = null;
	}

	private void _processChangeGeometry() {
		boolean isShapeChanged = _processChangeShape();
		boolean isColorChanged = _processChangeColor();

		if (isShapeChanged || isColorChanged) {
			_applyChangingGeometry();
		}
	}

	private boolean _processChangeShape() {
		boolean changed = false;

		if (!this.geometry.equals(buffer.geometry)) {
			changed = true;

			this.geometry = buffer.geometry;
			_createShpae();
		}

		return changed;
	}

	private boolean _processChangeColor() {
		boolean changed = false;

		if (!this.color.equals(buffer.color)) {
			changed = true;

			this.color = buffer.color;
			_createColorAtrribute();
		}

		return changed;
	}
}
